﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using HslCommunication.Core;
using HslCommunication.Core.IMessage;
using HslCommunication.Core.Net;
using HslCommunication.Reflection;

namespace HslCommunication.Profinet.Melsec
{
	/// <summary>
	/// 三菱PLC通讯协议，采用A兼容1E帧协议实现，使用二进制码通讯，请根据实际型号来进行选取<br />
	/// Mitsubishi PLC communication protocol, implemented using A compatible 1E frame protocol, using binary code communication, please choose according to the actual model
	/// </summary>
	/// <remarks>
	/// 本类适用于的PLC列表
	/// <list type="number">
	/// <item>FX3U(C) PLC   测试人sandy_liao</item>
	/// </list>
	/// 数据地址支持的格式如下：
	/// <list type="table">
	///   <listheader>
	///     <term>地址名称</term>
	///     <term>地址代号</term>
	///     <term>示例</term>
	///     <term>地址进制</term>
	///     <term>字操作</term>
	///     <term>位操作</term>
	///     <term>备注</term>
	///   </listheader>
	///   <item>
	///     <term>内部继电器</term>
	///     <term>M</term>
	///     <term>M100,M200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>输入继电器</term>
	///     <term>X</term>
	///     <term>X10,X20</term>
	///     <term>动态</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term>地址前面带0就是8进制比如X010，不带则是16进制，X40</term>
	///   </item>
	///   <item>
	///     <term>输出继电器</term>
	///     <term>Y</term>
	///     <term>Y10,Y20</term>
	///     <term>动态</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term>地址前面带0就是8进制比如Y020，不带则是16进制，Y40</term>
	///   </item>
	///   <item>
	///     <term>步进继电器</term>
	///     <term>S</term>
	///     <term>S100,S200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>报警器</term>
	///     <term>F</term>
	///     <term>F100,F200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>链接继电器</term>
	///     <term>B</term>
	///     <term>B1A0,B2A0</term>
	///     <term>16</term>
	///     <term>√</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>定时器触点</term>
	///     <term>TS</term>
	///     <term>TS0,TS100</term>
	///     <term>10</term>
	///     <term>×</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>定时器线圈</term>
	///     <term>TC</term>
	///     <term>TC0,TC100</term>
	///     <term>10</term>
	///     <term>×</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>定时器当前值</term>
	///     <term>TN</term>
	///     <term>TN0,TN100</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>计数器器触点</term>
	///     <term>CS</term>
	///     <term>CS0,CS100</term>
	///     <term>10</term>
	///     <term>×</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>计数器线圈</term>
	///     <term>CC</term>
	///     <term>CC0,CC100</term>
	///     <term>10</term>
	///     <term>×</term>
	///     <term>√</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>计数器当前值</term>
	///     <term>CN</term>
	///     <term>CN0,CN100</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>数据寄存器</term>
	///     <term>D</term>
	///     <term>D1000,D2000</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>链接寄存器</term>
	///     <term>W</term>
	///     <term>W0,W1A0</term>
	///     <term>16</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>文件寄存器</term>
	///     <term>R</term>
	///     <term>R100,R200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	/// </list>
	/// <see cref="M:HslCommunication.Profinet.Melsec.MelsecA1ENet.ReadBool(System.String,System.UInt16)" /> 方法一次读取的最多点数是256点。
	/// <note type="important">本通讯类由CKernal推送，感谢</note>
	/// </remarks>
	// Token: 0x02000065 RID: 101
	public class MelsecA1ENet : NetworkDeviceBase
	{
		/// <summary>
		/// 实例化一个默认的对象<br />
		/// Instantiate a default object
		/// </summary>
		// Token: 0x0600083A RID: 2106 RVA: 0x0002C8CB File Offset: 0x0002AACB
		public MelsecA1ENet()
		{
			base.WordLength = 1;
			base.ByteTransform = new RegularByteTransform();
		}

		/// <summary>
		/// 指定ip地址和端口来来实例化一个默认的对象<br />
		/// Specify the IP address and port to instantiate a default object
		/// </summary>
		/// <param name="ipAddress">PLC的Ip地址</param>
		/// <param name="port">PLC的端口</param>
		// Token: 0x0600083B RID: 2107 RVA: 0x0002C8F4 File Offset: 0x0002AAF4
		public MelsecA1ENet(string ipAddress, int port)
		{
			base.WordLength = 1;
			this.IpAddress = ipAddress;
			this.Port = port;
			base.ByteTransform = new RegularByteTransform();
		}

		/// <inheritdoc />
		// Token: 0x0600083C RID: 2108 RVA: 0x0002C92D File Offset: 0x0002AB2D
		protected override INetMessage GetNewNetMessage()
		{
			return new MelsecA1EBinaryMessage();
		}

		/// <summary>
		/// PLC编号，默认为0xFF<br />
		/// PLC number, default is 0xFF
		/// </summary>
		// Token: 0x1700017D RID: 381
		// (get) Token: 0x0600083D RID: 2109 RVA: 0x0002C934 File Offset: 0x0002AB34
		// (set) Token: 0x0600083E RID: 2110 RVA: 0x0002C93C File Offset: 0x0002AB3C
		public byte PLCNumber { get; set; } = byte.MaxValue;

		/// <inheritdoc />
		// Token: 0x0600083F RID: 2111 RVA: 0x0002C948 File Offset: 0x0002AB48
		[HslMqttApi("ReadByteArray", "")]
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<byte[]> operateResult = MelsecA1ENet.BuildReadCommand(address, length, false, this.PLCNumber);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<byte[]>(operateResult2);
				}
				else
				{
					OperateResult operateResult3 = MelsecA1ENet.CheckResponseLegal(operateResult2.Content);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<byte[]>(operateResult3);
					}
					else
					{
						result = MelsecA1ENet.ExtractActualData(operateResult2.Content, false);
					}
				}
			}
			return result;
		}

		/// <inheritdoc />
		// Token: 0x06000840 RID: 2112 RVA: 0x0002C9DC File Offset: 0x0002ABDC
		[HslMqttApi("WriteByteArray", "")]
		public override OperateResult Write(string address, byte[] value)
		{
			OperateResult<byte[]> operateResult = MelsecA1ENet.BuildWriteWordCommand(address, value, this.PLCNumber);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					OperateResult operateResult3 = MelsecA1ENet.CheckResponseLegal(operateResult2.Content);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<byte[]>(operateResult3);
					}
					else
					{
						result = OperateResult.CreateSuccessResult();
					}
				}
			}
			return result;
		}

		/// <inheritdoc />
		// Token: 0x06000841 RID: 2113 RVA: 0x0002CA5C File Offset: 0x0002AC5C
		[DebuggerStepThrough]
		public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
		{
			MelsecA1ENet.<ReadAsync>d__9 <ReadAsync>d__ = new MelsecA1ENet.<ReadAsync>d__9();
			<ReadAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
			<ReadAsync>d__.<>4__this = this;
			<ReadAsync>d__.address = address;
			<ReadAsync>d__.length = length;
			<ReadAsync>d__.<>1__state = -1;
			<ReadAsync>d__.<>t__builder.Start<MelsecA1ENet.<ReadAsync>d__9>(ref <ReadAsync>d__);
			return <ReadAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc />
		// Token: 0x06000842 RID: 2114 RVA: 0x0002CAB0 File Offset: 0x0002ACB0
		[DebuggerStepThrough]
		public override Task<OperateResult> WriteAsync(string address, byte[] value)
		{
			MelsecA1ENet.<WriteAsync>d__10 <WriteAsync>d__ = new MelsecA1ENet.<WriteAsync>d__10();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.value = value;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<MelsecA1ENet.<WriteAsync>d__10>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <summary>
		/// 批量读取<see cref="T:System.Boolean" />数组信息，需要指定地址和长度，地址示例M100，S100，B1A，如果是X,Y, X017就是8进制地址，Y10就是16进制地址。<br />
		/// Batch read <see cref="T:System.Boolean" /> array information, need to specify the address and length, return <see cref="T:System.Boolean" /> array. 
		/// Examples of addresses M100, S100, B1A, if it is X, Y, X017 is an octal address, Y10 is a hexadecimal address.
		/// </summary>
		/// <remarks>
		/// 根据协议的规范，最多读取256长度的bool数组信息，如果需要读取更长的bool信息，需要按字为单位进行读取的操作。
		/// </remarks>
		/// <param name="address">数据地址</param>
		/// <param name="length">数据长度</param>
		/// <returns>带有成功标识的byte[]数组</returns>
		// Token: 0x06000843 RID: 2115 RVA: 0x0002CB04 File Offset: 0x0002AD04
		[HslMqttApi("ReadBoolArray", "")]
		public override OperateResult<bool[]> ReadBool(string address, ushort length)
		{
			OperateResult<byte[]> operateResult = MelsecA1ENet.BuildReadCommand(address, length, true, this.PLCNumber);
			bool flag = !operateResult.IsSuccess;
			OperateResult<bool[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<bool[]>(operateResult);
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<bool[]>(operateResult2);
				}
				else
				{
					OperateResult operateResult3 = MelsecA1ENet.CheckResponseLegal(operateResult2.Content);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<bool[]>(operateResult3);
					}
					else
					{
						OperateResult<byte[]> operateResult4 = MelsecA1ENet.ExtractActualData(operateResult2.Content, true);
						bool flag4 = !operateResult4.IsSuccess;
						if (flag4)
						{
							result = OperateResult.CreateFailedResult<bool[]>(operateResult4);
						}
						else
						{
							result = OperateResult.CreateSuccessResult<bool[]>(Enumerable.ToArray<bool>(Enumerable.Take<bool>(Enumerable.Select<byte, bool>(operateResult4.Content, (byte m) => m == 1), (int)length)));
						}
					}
				}
			}
			return result;
		}

		/// <summary>
		/// 批量写入<see cref="T:System.Boolean" />数组数据，返回是否成功，地址示例M100，S100，B1A，如果是X,Y, X017就是8进制地址，Y10就是16进制地址。<br />
		/// Batch write <see cref="T:System.Boolean" /> array data, return whether the write was successful. 
		/// Examples of addresses M100, S100, B1A, if it is X, Y, X017 is an octal address, Y10 is a hexadecimal address.
		/// </summary>
		/// <param name="address">起始地址</param>
		/// <param name="value">写入值</param>
		/// <returns>带有成功标识的结果类对象</returns>
		// Token: 0x06000844 RID: 2116 RVA: 0x0002CBF4 File Offset: 0x0002ADF4
		[HslMqttApi("WriteBoolArray", "")]
		public override OperateResult Write(string address, bool[] value)
		{
			OperateResult<byte[]> operateResult = MelsecA1ENet.BuildWriteBoolCommand(address, value, this.PLCNumber);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					result = MelsecA1ENet.CheckResponseLegal(operateResult2.Content);
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecA1ENet.ReadBool(System.String,System.UInt16)" />
		// Token: 0x06000845 RID: 2117 RVA: 0x0002CC50 File Offset: 0x0002AE50
		[DebuggerStepThrough]
		public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
		{
			MelsecA1ENet.<ReadBoolAsync>d__13 <ReadBoolAsync>d__ = new MelsecA1ENet.<ReadBoolAsync>d__13();
			<ReadBoolAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
			<ReadBoolAsync>d__.<>4__this = this;
			<ReadBoolAsync>d__.address = address;
			<ReadBoolAsync>d__.length = length;
			<ReadBoolAsync>d__.<>1__state = -1;
			<ReadBoolAsync>d__.<>t__builder.Start<MelsecA1ENet.<ReadBoolAsync>d__13>(ref <ReadBoolAsync>d__);
			return <ReadBoolAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Melsec.MelsecA1ENet.Write(System.String,System.Boolean[])" />
		// Token: 0x06000846 RID: 2118 RVA: 0x0002CCA4 File Offset: 0x0002AEA4
		[DebuggerStepThrough]
		public override Task<OperateResult> WriteAsync(string address, bool[] values)
		{
			MelsecA1ENet.<WriteAsync>d__14 <WriteAsync>d__ = new MelsecA1ENet.<WriteAsync>d__14();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.values = values;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<MelsecA1ENet.<WriteAsync>d__14>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc />
		// Token: 0x06000847 RID: 2119 RVA: 0x0002CCF6 File Offset: 0x0002AEF6
		public override string ToString()
		{
			return string.Format("MelsecA1ENet[{0}:{1}]", this.IpAddress, this.Port);
		}

		/// <summary>
		/// 根据类型地址长度确认需要读取的指令头
		/// </summary>
		/// <param name="address">起始地址</param>
		/// <param name="length">长度</param>
		/// <param name="isBit">指示是否按照位成批的读出</param>
		/// <param name="plcNumber">PLC编号</param>
		/// <returns>带有成功标志的指令数据</returns>
		// Token: 0x06000848 RID: 2120 RVA: 0x0002CD14 File Offset: 0x0002AF14
		public static OperateResult<byte[]> BuildReadCommand(string address, ushort length, bool isBit, byte plcNumber)
		{
			OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				byte b = isBit ? 0 : 1;
				result = OperateResult.CreateSuccessResult<byte[]>(new byte[]
				{
					b,
					plcNumber,
					10,
					0,
					BitConverter.GetBytes(operateResult.Content2)[0],
					BitConverter.GetBytes(operateResult.Content2)[1],
					BitConverter.GetBytes(operateResult.Content2)[2],
					BitConverter.GetBytes(operateResult.Content2)[3],
					operateResult.Content1.DataCode[1],
					operateResult.Content1.DataCode[0],
					(byte)(length % 256),
					0
				});
			}
			return result;
		}

		/// <summary>
		/// 根据类型地址以及需要写入的数据来生成指令头
		/// </summary>
		/// <param name="address">起始地址</param>
		/// <param name="value">数据值</param>
		/// <param name="plcNumber">PLC编号</param>
		/// <returns>带有成功标志的指令数据</returns>
		// Token: 0x06000849 RID: 2121 RVA: 0x0002CDE4 File Offset: 0x0002AFE4
		public static OperateResult<byte[]> BuildWriteWordCommand(string address, byte[] value, byte plcNumber)
		{
			OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				byte[] array = new byte[12 + value.Length];
				array[0] = 3;
				array[1] = plcNumber;
				array[2] = 10;
				array[3] = 0;
				array[4] = BitConverter.GetBytes(operateResult.Content2)[0];
				array[5] = BitConverter.GetBytes(operateResult.Content2)[1];
				array[6] = BitConverter.GetBytes(operateResult.Content2)[2];
				array[7] = BitConverter.GetBytes(operateResult.Content2)[3];
				array[8] = operateResult.Content1.DataCode[1];
				array[9] = operateResult.Content1.DataCode[0];
				array[10] = BitConverter.GetBytes(value.Length / 2)[0];
				array[11] = BitConverter.GetBytes(value.Length / 2)[1];
				Array.Copy(value, 0, array, 12, value.Length);
				result = OperateResult.CreateSuccessResult<byte[]>(array);
			}
			return result;
		}

		/// <summary>
		/// 根据类型地址以及需要写入的数据来生成指令头
		/// </summary>
		/// <param name="address">起始地址</param>
		/// <param name="value">数据值</param>
		/// <param name="plcNumber">PLC编号</param>
		/// <returns>带有成功标志的指令数据</returns>
		// Token: 0x0600084A RID: 2122 RVA: 0x0002CEC8 File Offset: 0x0002B0C8
		public static OperateResult<byte[]> BuildWriteBoolCommand(string address, bool[] value, byte plcNumber)
		{
			OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				byte[] array = MelsecHelper.TransBoolArrayToByteData(value);
				byte[] array2 = new byte[12 + array.Length];
				array2[0] = 2;
				array2[1] = plcNumber;
				array2[2] = 10;
				array2[3] = 0;
				array2[4] = BitConverter.GetBytes(operateResult.Content2)[0];
				array2[5] = BitConverter.GetBytes(operateResult.Content2)[1];
				array2[6] = BitConverter.GetBytes(operateResult.Content2)[2];
				array2[7] = BitConverter.GetBytes(operateResult.Content2)[3];
				array2[8] = operateResult.Content1.DataCode[1];
				array2[9] = operateResult.Content1.DataCode[0];
				array2[10] = BitConverter.GetBytes(value.Length)[0];
				array2[11] = BitConverter.GetBytes(value.Length)[1];
				Array.Copy(array, 0, array2, 12, array.Length);
				result = OperateResult.CreateSuccessResult<byte[]>(array2);
			}
			return result;
		}

		/// <summary>
		/// 检测反馈的消息是否合法
		/// </summary>
		/// <param name="response">接收的报文</param>
		/// <returns>是否成功</returns>
		// Token: 0x0600084B RID: 2123 RVA: 0x0002CFB4 File Offset: 0x0002B1B4
		public static OperateResult CheckResponseLegal(byte[] response)
		{
			bool flag = response.Length < 2;
			OperateResult result;
			if (flag)
			{
				result = new OperateResult(StringResources.Language.ReceiveDataLengthTooShort);
			}
			else
			{
				bool flag2 = response[1] == 0;
				if (flag2)
				{
					result = OperateResult.CreateSuccessResult();
				}
				else
				{
					bool flag3 = response[1] == 91;
					if (flag3)
					{
						result = new OperateResult((int)response[2], StringResources.Language.MelsecPleaseReferToManualDocument);
					}
					else
					{
						result = new OperateResult((int)response[1], StringResources.Language.MelsecPleaseReferToManualDocument);
					}
				}
			}
			return result;
		}

		/// <summary>
		/// 从PLC反馈的数据中提取出实际的数据内容，需要传入反馈数据，是否位读取
		/// </summary>
		/// <param name="response">反馈的数据内容</param>
		/// <param name="isBit">是否位读取</param>
		/// <returns>解析后的结果对象</returns>
		// Token: 0x0600084C RID: 2124 RVA: 0x0002D028 File Offset: 0x0002B228
		public static OperateResult<byte[]> ExtractActualData(byte[] response, bool isBit)
		{
			OperateResult<byte[]> result;
			if (isBit)
			{
				byte[] array = new byte[(response.Length - 2) * 2];
				for (int i = 2; i < response.Length; i++)
				{
					bool flag = (response[i] & 16) == 16;
					if (flag)
					{
						array[(i - 2) * 2] = 1;
					}
					bool flag2 = (response[i] & 1) == 1;
					if (flag2)
					{
						array[(i - 2) * 2 + 1] = 1;
					}
				}
				result = OperateResult.CreateSuccessResult<byte[]>(array);
			}
			else
			{
				result = OperateResult.CreateSuccessResult<byte[]>(response.RemoveBegin(2));
			}
			return result;
		}
	}
}
